package com.example.netty.sockettwo;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class NettyServerTwo {
    /**
     * boss 线程组用于处理连接工作
     * 创建一个线程组：用来处理网络事件（接受客户端连接）
     */
    private EventLoopGroup boss = new NioEventLoopGroup();
    /**
     * work 线程组用于数据处理
     * 创建一个线程组：用来处理网络事件（处理通道 IO 操作）
     */
    private EventLoopGroup work = new NioEventLoopGroup();

    private Integer port=9997;
    ChannelFuture future=null;


    @PostConstruct
    public void start() throws InterruptedException {
        ServerBootstrap bootstrap = new ServerBootstrap();//3.创建服务器端启动助手来配置参数
        bootstrap.group(boss, work) //4.设置两个线程组 EventLoopGroup
                // 指定Channel
                //使用 NioServerSocketChannel 作为服务器
                .channel(NioServerSocketChannel.class)
                //使用指定的端口设置套接字地址
                .localAddress(new InetSocketAddress(port))

                //服务端可连接队列数,对应TCP/IP协议listen函数中backlog参数
                //6.设置线程队列中等待连接的个数
                .option(ChannelOption.SO_BACKLOG, 1024)

                //设置TCP长连接,一般如果两个小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文
                //保持活动连接状态
                .childOption(ChannelOption.SO_KEEPALIVE, true)

                //将小的数据包包装成更大的帧进行传送，提高网络的负载
                .childOption(ChannelOption.TCP_NODELAY, true)

                .childHandler(new ChannelInitializer<SocketChannel>(){
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        //添加编解码
                        socketChannel.pipeline().addLast(new CustomHexDecoderTwo());
                        socketChannel.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));
                        socketChannel.pipeline().addLast(new NettyServerHandlerTwo());
                    }
                });
        //启动服务器端并绑定端口，等待接受客户端连接(非阻塞) 这里也可以绑定端口
         future = bootstrap.bind().sync();
        if (future.isSuccess()) {
            log.info("启动 Netty Server");
        }

    }
    @PreDestroy
    public void destory() throws InterruptedException {
        log.info("关闭====》");
        //关闭通道
        future.channel().closeFuture().sync();
        //关闭线程池
        boss.shutdownGracefully().sync();
        work.shutdownGracefully().sync();
        log.info("关闭Netty");
    }


}
